﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DTBuilderLib.VisualHierarchyClasses;
using DTBuilderLib;
using System.Drawing;
using System.IO;

namespace t_SparseImageTool
{
    /// <summary>
    /// Test generating mutliple images in a row.
    /// </summary>
    [TestClass]
    public class MultiImageTest
    {
        public MultiImageTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void TestTwoImagesInsideOne()
        {
            VisualBitmapImage b1 = new VisualBitmapImage(11.0F, 8.5F, 300, Color.Black);
            VisualBitmapImage b2 = new VisualBitmapImage(6.0F, 6F, 300, Color.Black);

            b2.XPosition = 1.0F;
            VisualHolder vh = new VisualHolder();
            vh.AddImage(b1);
            vh.AddImage(b2);

            double width = vh.Width;
            vh.Scale(1.0F / width);

            DeepZoomBuilder bld = new DeepZoomBuilder();
            DirectoryInfo inf = new DirectoryInfo(".\\TestTwoImagesInsideOne");
            bld.BuildDirectory = inf.FullName;
            DirectoryInfo rend = bld.RenderVisual("TestTwoImagesInsideOne", vh);

            /// It will throw if it fails - good enough for this test.
        }

        [TestMethod]
        public void TestTwoImages()
        {
            VisualBitmapImage b1 = new VisualBitmapImage(11.0F, 8.5F, 300, Color.Black);
            VisualBitmapImage b2 = new VisualBitmapImage(11.0F, 8.5F, 300, Color.Black);

            b2.XPosition = 11.2F;
            VisualHolder vh = new VisualHolder();
            vh.AddImage(b1);
            vh.AddImage(b2);

            DeepZoomBuilder bld = new DeepZoomBuilder();
            DirectoryInfo inf = new DirectoryInfo(".\\TestTwoImages");
            bld.BuildDirectory = inf.FullName;
            DirectoryInfo rend = bld.RenderVisual("TestTwoImages", vh);

            /// It will throw if it fails - good enough for this test.
        }

        [TestMethod]
        public void Test2ImagesAsComposition()
        {
            TestMultiImagesCompositon(2);
        }

        [TestMethod]
        public void Test1Image()
        {
            TestMultiImages(1);
        }

        [TestMethod]
        public void Test2ImagesByAutoMethod()
        {
            TestMultiImages(2);
        }

        [TestMethod]
        public void Test10Images()
        {
            TestMultiImages(10);
        }

        [TestMethod]
        public void Test30Images()
        {
            TestMultiImages(30);
        }

        [TestMethod]
        public void Test100Images()
        {
            TestMultiImages(100);
        }

        [TestMethod]
        public void Test200Images()
        {
            TestMultiImages(200);
        }

        [TestMethod]
        public void Inside2x2()
        {
            TestNestedImages(2, 2);
        }

        [TestMethod]
        public void Inside4x2()
        {
            TestNestedImages(4, 2);
        }

        [TestMethod]
        public void Inside4x20()
        {
            TestNestedImages(4, 20);
        }

        private void TestNestedImages(int levels, int numberPerLevel)
        {
            DirectoryInfo tempImages = new DirectoryInfo(".\\" + TestContext.TestName + "\\images");
            tempImages.Create();

            VisualHolder images = BuildNestedImages(tempImages, levels, numberPerLevel);
            DeepZoomBuilder bld = new DeepZoomBuilder();
            DirectoryInfo inf = new DirectoryInfo(".\\" + TestContext.TestName);
            bld.BuildDirectory = inf.FullName;
            DirectoryInfo rnd = bld.RenderVisual(TestContext.TestName, images);
        }

        /// <summary>
        /// Build a set of nested images. Recursive routine - so watch the memory!
        /// </summary>
        /// <param name="tempImages"></param>
        /// <param name="levels"></param>
        /// <param name="numberPerLevel"></param>
        /// <returns></returns>
        private VisualHolder BuildNestedImages(DirectoryInfo tempImages, int levels, int numberPerLevel)
        {
            if (levels == 1)
            {
                return BuildImagesInARow(numberPerLevel, tempImages);
            }

            /// Create the master
            VisualHolder master = BuildImagesInARow(numberPerLevel, tempImages, Color.Red);

            /// Get the images that we will put together, and place them in the master image
            double lastX = 0.0;
            for (int i = 0; i < numberPerLevel; i++)
            {
                Visual row = BuildNestedImages(tempImages, levels - 1, numberPerLevel);
                row.RescaleToFit(11.0*0.9, 8.5*0.9);

                lastX = lastX + 11.0 * 0.05;
                row.IncZIndex();
                row.XPosition = lastX;
                row.YPosition = 8.5 * 0.05;
                master.AddImage(row);
                lastX = lastX + 11.0 * 0.95;
            }

            return master;
        }

        /// <summary>
        /// Generate a series of images - but each image is a seperate composition.
        /// </summary>
        /// <param name="p"></param>
        private void TestMultiImagesCompositon(int p)
        {
            DirectoryInfo tempImages = new DirectoryInfo(".\\" + TestContext.TestName + "\\images");
            tempImages.Create();

            var images = BuildImagesInARow(p, tempImages, Color.Purple, true);

            DeepZoomBuilder bld = new DeepZoomBuilder();
            DirectoryInfo inf = new DirectoryInfo(".\\" + TestContext.TestName);
            bld.BuildDirectory = inf.FullName;
            DirectoryInfo rnd = bld.RenderVisual(TestContext.TestName, images);

            Assert.IsTrue (File.Exists(rnd.FullName + "\\token.txt"), "Token file was missing!");
        }

        /// <summary>
        /// Run test on multiple images.
        /// </summary>
        /// <param name="p"></param>
        private void TestMultiImages(int n)
        {
            DirectoryInfo tempImages = new DirectoryInfo(".\\" + TestContext.TestName + "\\images");
            tempImages.Create();

            VisualHolder vh = BuildImagesInARow(n, tempImages);

            DeepZoomBuilder bld = new DeepZoomBuilder();
            DirectoryInfo inf = new DirectoryInfo(".\\" + TestContext.TestName);
            bld.BuildDirectory = inf.FullName;
            DirectoryInfo rnd = bld.RenderVisual(TestContext.TestName, vh);
        }

        /// <summary>
        /// Puts the images in a row and returns a holder for them.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="tempImages"></param>
        /// <returns></returns>
        private static VisualHolder BuildImagesInARow(int n, DirectoryInfo tempImages, Color c, bool eachAsComposition)
        {
            VisualHolder vh = new VisualHolder();
            double last_x = 0.0;

            for (int i = 0; i < n; i++)
            {
                VisualBitmapImage b = new VisualBitmapImage(11.0F, 8.5F, 600, c);
                b.ImageWritingDirectory = tempImages;
                b.XPosition = last_x;
                b.IsCompositionUnit = eachAsComposition;
                last_x += b.Width + 0.2F;
                vh.AddImage(b);
            }
            return vh;
        }

        private static VisualHolder BuildImagesInARow(int n, DirectoryInfo tempImages)
        {
            return BuildImagesInARow(n, tempImages, Color.Beige, false);
        }
        private static VisualHolder BuildImagesInARow(int n, DirectoryInfo tempImages, Color c)
        {
            return BuildImagesInARow(n, tempImages, c, false);
        }
    }

    static class VisualExtensionMethods
    {
        /// <summary>
        /// Make sure that the visual is no bigger in either direction.
        /// </summary>
        /// <param name="v"></param>
        /// <param name="xmax"></param>
        /// <param name="ymax"></param>
        public static void RescaleToFit(this Visual v, double xmax, double ymax)
        {
            double scale = 1.0;
            double xscale = CalcScale(v.Width, xmax);
            double yscale = CalcScale(v.Height, ymax);
            scale = scale > xscale ? xscale : scale;
            scale = scale > yscale ? yscale : scale;
            v.Scale(scale);
        }

        private static double CalcScale(double p, double xmax)
        {
            if (p > xmax)
            {
                return xmax / p;
            }
            return 1.0;
        }
    }
}
